package com.mj.myvirtualapp;

import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.Application;
import android.app.IActivityManager;
import android.app.Instrumentation;
import android.content.Context;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.os.Build;
import android.os.Environment;
import android.util.Log;
import android.util.Singleton;

import com.mj.myvirtualapp.utils.DexUtil;
import com.mj.myvirtualapp.utils.ReflectUtil;

import java.io.File;

import dalvik.system.DexClassLoader;

public class App extends Application {
    File apkFile;
    public DexClassLoader pluginClassLoader;
    public VAInstrumentation mInstrumentation;
    static App app;
    static String TAG = "app";
    public Resources resources;
    private IActivityManager mActivityManager;

    @Override
    public void onCreate() {
        super.onCreate();


        app = this;
        apkFile = new File(Environment.getExternalStorageDirectory(), "plugin.apk");
        resources = getPluginResource();
        pluginClassLoader = getPluginClassLoader();
        try {
            //合并dex，这样
            DexUtil.insertDex(pluginClassLoader);
            Log.e(TAG, "合并dex成功");
        } catch (Exception e) {
            e.printStackTrace();
        }
        hookSystemServices();
        hookInstrumentationAndHandler();

//        try {
//            Class<?> aClass = getClassLoader().loadClass("com.mj.myvirtualapp.plugin.MainActivity");
//            Log.e(TAG, aClass+"");
//        } catch (ClassNotFoundException e) {
//            e.printStackTrace();
//            Log.e(TAG, e+"");
//        }


    }

    public static App getApp() {
        return app;
    }

    private void hookInstrumentationAndHandler() {
        try {
            Instrumentation baseInstrumentation = ReflectUtil.getInstrumentation(this);
            if (baseInstrumentation.getClass().getName().contains("lbe")) {
                // reject executing in paralell space, for example, lbe.
                System.exit(0);
            }

            final VAInstrumentation instrumentation = new VAInstrumentation(baseInstrumentation);
            Object activityThread = ReflectUtil.getActivityThread(this);
            ReflectUtil.setInstrumentation(activityThread, instrumentation);
            ReflectUtil.setHandlerCallback(this, instrumentation);
            this.mInstrumentation = instrumentation;
            Log.e(TAG, "hookInstrumentationAndHandler成功");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private void hookSystemServices() {
        try {
            Singleton<IActivityManager> defaultSingleton;

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                defaultSingleton = (Singleton<IActivityManager>) ReflectUtil.getField(ActivityManager.class, null, "IActivityManagerSingleton");
            } else {
                defaultSingleton = (Singleton<IActivityManager>) ReflectUtil.getField(ActivityManagerNative.class, null, "gDefault");
            }
            IActivityManager activityManagerProxy = ActivityManagerProxy.newInstance(defaultSingleton.get());

            // Hook IActivityManager from ActivityManagerNative
            ReflectUtil.setField(defaultSingleton.getClass().getSuperclass(), defaultSingleton, "mInstance", activityManagerProxy);

            if (defaultSingleton.get() == activityManagerProxy) {
                this.mActivityManager = activityManagerProxy;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    private DexClassLoader getPluginClassLoader() {
        File dexOutputDir = this.getDir("odex_plugin", Context.MODE_PRIVATE);
        File libsDir = this.getDir("so_libs_plugin", Context.MODE_PRIVATE);
        DexClassLoader loader = new DexClassLoader(apkFile.getAbsolutePath(), dexOutputDir.getAbsolutePath(), libsDir.getAbsolutePath(), getClassLoader());
        return loader;

    }

    private Resources getPluginResource() {
        Resources hostResources = this.getResources();
        try {
            AssetManager assetManager = AssetManager.class.newInstance();
            ReflectUtil.invoke(AssetManager.class, assetManager, "addAssetPath", apkFile.getAbsolutePath());
            return new Resources(assetManager, hostResources.getDisplayMetrics(), hostResources.getConfiguration());
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }


    }
}
